var event = require('../../core/event');
var util = require('../../util/index');
var Log = require('../../util/logger');
var note = require('../note/manager');
var frac = require('../../util/frac');
var sample = require('../sample/manager');
var sound = require('../audio/sound');
var timing = require('../timing/manager');
var config = require('../../core/config');

/***
 * 负责note的编辑
 *
 * note单元的结构
 * {
 *    "beat":[1,0,0],
 *    "column":0
 * }
 */

var _init = false;

var ui = null;

var ret = {
	init: function(){
		if(_init){
			return;
		}
		this.chart = null;
		this.sorted = false;
		this.noteIndex = 0;

		timing.init();

		event.bindOwner('note', 'grid', this);
		event.bindOwner('grid', 'grid', this);
		event.bind(event.events.dialog.grid, 'grid', this);
		event.bind(event.events.timing.change, 'grid', this);
		event.bind(event.events.dialog.grid, 'grid', this);
		event.bind(event.events.dialog.gridaux, 'grid', this);
		event.bind(event.events.dialog.movenote, 'grid', this);
		_init = true;
	},

	onEvent: function(e, param){
		if(e == event.events.note.load){
			this.chart = note.getNote(param.key);
			this.noteIndex = 0;
			this.validate();
			this.sortNotes();

			timing.load(this.chart);
			this.loadSamples();

			if(ui != null){
				ui.clear();
				ui.release();
			}
			var mode = this.chart.meta.mode;

			var _clazz;
			if(mode == note.MODE.CATCH){
				_clazz = require('./ui-catch.js');
			}else if(mode == note.MODE.UBEAT){
                _clazz = require('./ui-ubeat.js');
			}else if(mode == note.MODE.TAIKO){
				_clazz = require('./ui-taiko.js');
			}else{
				_clazz = require('./ui.js');
			}
			ui = new _clazz();
			ui.setManager(this);
			ui.init();
			ui.show();
			ui.sync(param.mce);
		}else if(e == event.events.note.unload){
			this.chart = null;
			this.timeTable = null;
			if(ui){
				ui.hide();
				ui.clear();
				ui.release();
			}

			ui = null;
		}else if(e == event.events.dialog.grid) {
			if(!this.chart) {
				return;
			}
			var _gridConfig = require('./dialog/setting.js');
			_gridConfig.setManager(this);
			_gridConfig.init();
			_gridConfig.show(this.chart);
			return event.result.stopAll;
		}else if(e == event.events.dialog.gridaux) {
			if (!this.chart) {
				return;
			}
			var dialog = require('./dialog/gridaux.js');
			dialog.setManager(this);
			dialog.init();
			dialog.show(this.chart);
			return event.result.stopAll;
		}else if(e == event.events.dialog.movenote){
			if (!this.chart) {
				return;
			}
			var dialog = require('./dialog/move.js');
			dialog.setManager(this);
			dialog.init();
			dialog.show(this.chart);
			return event.result.stopAll;
		}else if(e == event.events.timing.change){
			this.loadSamples();
			if(ui){
				ui.updateGrid();
			}
		}else if(e == event.events.grid.sync){
			if(ui){
                var isMCE = param && param.isMCE;
				ui.sync(isMCE);
				return event.result.stopAll;
			}
		}else if(e == event.events.grid.align){
			this.sortNotes();
		}else if(e == event.events.note.touch){
			if(!ui){
				return;
			}
			if(!window.confirm(config.i18n("tip08"))){
				return event.result.stopAll;
			}
			var mod = require('./plugin/auto.js');
			mod.setManager(this);
			mod.init(this);

			this.sortNotes();
			mod.toTouch(this.chart);
			ui.sync();
		}
	},

	/**
	 * 内部, 静默的检查Chart各种参数的合法性
	 * Chart从外部输入, 默认只检查几个关键路径参数
	 * 假定this.chart 已存在
	 */
	validate: function(){
		if(!this.chart.note){
			this.chart.note = [];
		}
		if (!this.chart.time) {
			this.chart.time = [];
		}
		if(!this.chart.extra){
			this.chart.extra = {};
		}
		this.chart.extra.toggle = this.chart.extra.toggle || [];
		//确保每个note都有id
		//如果存在无id note(意外发生了), 那么给他们分配一个可用id
		//id伴随note整个edit过程, 唯一标识
		//有效id从1开始
		var pending = [];
		var maxId = 0;
		for(var i=0;i<this.chart.note.length;i++){
			var _note = this.chart.note[i];
			if(!_note.id){
				pending.push(_note);
			}else if(_note.id > maxId){
				maxId = _note.id;
			}
			if(_note.tid){
				_note.tid = -1; //干掉track id
			}
		}
		for(var i=0;i<pending.length;i++){
			pending[i].id = ++maxId;
		}
		this.noteIndex = maxId;
	},

	/***
	 * 查询接口
	 */

	getNote: function(id){
		if(!this.chart){
			return null;
		}
		var idx = this.findNoteById({id: id});
		if(idx >= 0){
			return this.chart.note[idx];
		}
		return null;
	},

	getNotes: function(){
		if(!this.chart){
			return null;
		}
		return this.chart.note;
	},

	/**
	 * 获取选中的note
     * 注意这里的arg支持参数allMode，表示也考虑pad模式的note
     * 这个参数的加入是为了防止某些只针对key模式的note操作函数混入pad的note要出错
	 */
	getSelectNotes: function(args){
		var arr = ui.getSelectIds(args);
		var ret = [];
		for(var i=0;i<arr.length;i++){
			ret.push(this.getNote(arr[i]));
		}
		return ret;
	},

	getSelectIds: function(args) {
		return ui.getSelectIds(args);
	},

	//获得当前最大beat数
	getTotalBeat: function(){
		if(!this.chart){
			return 0;
		}
		if(!this.sorted){
			this.sortNotes();
		}
		var len = this.chart.note.length;
		if(len == 0){
			return 0;
		}
		//默认有序, 其他地方排好序
		var obj = this.chart.note[len - 1];
		return obj.beat[0] + 1;
	},

	getMaxNoteTime: function () {
		var beat = this.getTotalBeat();
		return timing.beatToTime([beat, 0, 1]);
	},

	isNoteExist: function(obj){
		return this.findNote(obj) >= 0;
	},

	getEditInfo: function(){
		return this.chart.extra
	},

	/**
	 * 传入任意坐标, 得到这个坐标上的note, 或者覆盖这个坐标的note(hold)
	 */
	findAnyNote: function(obj){
		if(!this.chart){
			return null;
		}
		for(var i=this.chart.note.length-1;i>=0;i--){
			var note = this.chart.note[i];
			if(typeof note["column"] != 'undefined' && note.column != obj.column){
				continue;
			}
			if(typeof note["x"] != 'undefined' && Math.abs(note.x - obj.x) > 10){
				continue;
			}
			if(frac.compare(note.beat, obj.beat) == 0){
				return note;
			}
			//hold check
			if(!note.endbeat){
				continue;
			}
			if(frac.compare(note.beat, obj.beat) <= 0 && frac.compare(note.endbeat, obj.beat) >= 0){
				return note;
			}
		}
		return null;
	},

	/**
	 * note操纵接口
	 */

	addNote: function(obj){
		if(!this.chart){
			return;
		}
		obj.id = ++this.noteIndex;
		this.chart.note.push(obj);
		this.sorted = false;
		event.trigger(event.events.note.change);
		return this.noteIndex;
	},

    addNoteWithoutNewId : function(obj){
        if(!this.chart){
            return;
        }
        this.chart.note.push(obj);
        this.sorted = false;
        event.trigger(event.events.note.change);
    },

	removeNote: function(id){
		if(!this.chart){
			return;
		}
		var idx = this.findNoteById({id: id});
		if(idx >= 0){
			var curr = this.chart.note[idx];
			if (curr.tid >= 0) {
				sound.removeCell(curr.tid);
				//sound.unload(sample.getSample(curr.sound));
			}
			this.chart.note.splice(idx, 1);
		}
		event.trigger(event.events.note.change);
	},

	removeNotes: function(ids){
		if(!this.chart){
			return;
		}
		if(!this.sorted){
			this.sortNotes();
		}
		//有序列表进行删除后还是有序的
		for(var i=0;i<ids.length;i++){
			var id = ids[i];
			var idx = this.findNoteById({id: id});
			if(idx >= 0){
				var curr = this.chart.note[idx];
				if (curr.tid >= 0) {
					sound.removeCell(curr.tid);
					//sound.unload(sample.getSample(curr.sound));
				}
				this.chart.note.splice(idx, 1);
			}
		}
		event.trigger(event.events.note.change);
	},

	/**
	 * 复制note, 因为涉及note的多种属性复制, 放这里
	 * @param note
	 */
	copyNote: function(note){
		var _note = util.cloneObject(note);
		delete _note.tid;
		delete _note.id;
		delete _note.time;
		delete _note.endtime;
		return _note;
	},

	/**
	 * 内部计算辅助
	 */

	compareNote: function(a, b){
		var cmpBeat = frac.compare(a.beat, b.beat);
		if (cmpBeat == 0) {
			if(a.column == b.column){
				return 0;
			}else if(a.column < b.column){
				return -1;
			}else{
				return 1;
			}
		} else {
			return cmpBeat;
		}
	},

	/**
	 * note有序就二分, 无序就遍历
	 * @param obj
	 * @returns {*}
	 */
	findNote: function(obj){
		var self = this;
		if(this.sorted){
			var index = util.binaryFindIndex(this.chart.note, function(item){
				return self.compareNote(obj, item);
			});
			if(index < 0 || this.compareNote(this.chart.note[index], obj) != 0){
				return -1;
			}
			return index;
		}else{
			for(var i=this.chart.note.length-1;i>=0;i--){
				if(this.compareNote(this.chart.note[i], obj) == 0){
					return i;
				}
			}
			return -1;
		}
	},

	findNoteById: function(obj){
		if(!obj.id){
			return this.findNote(obj);
		}
		for(var i=this.chart.note.length-1;i>=0;i--){
			if(this.chart.note[i].id == obj.id){
				return i;
			}
		}
		return -1;
	},

	sortNotes: function(){
		if(!this.chart){
			return;
		}
		var self = this;
		this.chart.note.sort(function(a, b){
			return self.compareNote(a,b);
		});
		this.sorted = true;
	},

    //获取有非bgm音符的轨道 并进行排序
    getAvailableTracks : function(includeMusicTrack){
        var track = {};
        var chart = this.chart;
        var notes = this.getSelectNotes();
        var tidMax = 0;
        var tidMin = 999;
        //获得有音符区域的最大长度
        for(var i = 0; i < notes.length ; i++){
            var note = notes[i];
            var column = note.column;
            track[column] = 1;
            tidMax = column > tidMax ? column : tidMax;
            tidMin = column < tidMin ? column : tidMin;
        }
        //将tidMax和tidMin之间的轨道全部打上记号
        var ret = [];
        for(var i = tidMin ; i <= tidMax ; i++ ){
            ret.push(i);
        }
        return ret;
    },

	// 加载note的sample，要求timeTable准备完毕
	loadSamples: function() {
		if (!this.chart) {
			return;
		}
		sound.clearTrack();
		var len = this.chart.note.length;
		for (var i = 0;i<len;i++) {
			var curr = this.chart.note[i];
			if (!curr.sound) {
				continue;
			}
			var offset = timing.beatToTime(curr.beat);
			if(curr.offset){
				offset += curr.offset;
			}
			curr.tid = sound.addCell(note.getFilePath(curr.sound), curr.vol || 30, offset);
		}
	}
};

module.exports = ret;